/*
 * Alloy Analyzer
 * Copyright (c) 2004 Massachusetts Institute of Technology
 *
 * The Alloy Analyzer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * The Alloy Analyzer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Alloy Analyzer; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package alloy.gui;

import java.awt.Component;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.ref.SoftReference;
import java.util.Date;

import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.StyleSheet;

import alloy.api.Instance;
import alloy.api.SolutionData;
import alloy.ast.Command;
import alloy.util.ParameterEvent;
import alloy.util.ParameterListener;
import alloy.util.Params;
import alloy.util.TmpFiles;
import alloy.util.XSLT;
import alloy.viz.gui.VizPanel;

/** A SuccessfulAnalysis represents an "execute" or "next" operation that generated an instance.
 */

class SuccessfulAnalysis extends Analysis {
    private final SolutionData _instance;

    AlloyWindow evalFrame;
    JComponent treeComponent, textComponent, xmlComponent, xmlAbbrevComponent, tableComponent, dotComponent;
    SoftReference softVizPanel; // reference to VizPanel

    ParameterListener treeFontUpdater, textFontUpdater;

    SuccessfulAnalysis(
		       String name_,
		       ModelPanel textWindow_,
		       String modelString_,
		       Command.Info commandInfo_,
		       Date startTime_,
		       long durationMillis_,
		       SolutionData instance_) {
	super(name_, textWindow_, modelString_, commandInfo_, startTime_, durationMillis_);

	_instance = instance_;

	String filePath = getFilePanel().getTextArea().getFilePath();

    }

    public void setName(String name_) {
	super.setName(name_);
	if (evalFrame != null)
	    evalFrame.setTitle(name_ + " - Evaluator");
    }

    VizPanel getVizPanel() {
	if (softVizPanel != null && softVizPanel.get() != null)
	    return (VizPanel)softVizPanel.get();

	String filePath = getFilePanel().getTextArea().getFilePath();
	VizPanel vizPanel =
	    new VizPanel(_instance.getVizInstance(),
			 new alloy.api.AlloyEvaluator(_instance),
			 filePath);
	softVizPanel = new SoftReference(vizPanel);
	return vizPanel;
    }

    JComponent getTreeComponent() {
	if (treeComponent != null) return treeComponent;
	    
	final SolutionTree solTree = new SolutionTree();
	solTree.setupSignatureNodes(_instance);
	solTree.setFont(Params.glob.getFontParam("GUI", "treefont"));
	    
	treeFontUpdater = new ParameterListener() {
		public void valueChanged(ParameterEvent e) {
		    solTree.setFont(Params.glob.getFontParam("GUI", "treefont"));
		}
	    };
	Params.glob.addParameterListener("GUI","treefont",treeFontUpdater);
	    
	return treeComponent = solTree.getComponent();
    }
	
    JComponent getTextComponent() {
	    if (textComponent != null) return textComponent;
	    return textComponent = makeTextArea( _instance.toString() );
    }
	
    JComponent getXmlTextComponent() {
	    if (xmlComponent != null) return xmlComponent;
	    return xmlComponent = makeTextArea( ((Instance)_instance).toXML() );
    }

    public Component getXmlAbbrevTextComponent() {
	    if (xmlAbbrevComponent != null) return xmlAbbrevComponent;
	    return xmlAbbrevComponent = makeTextArea( XSLT.abbreviateSolution(((Instance)_instance).toXML()) );
    }

    public Component getTableComponent() {
	    if (tableComponent != null) return tableComponent;
	    tableComponent = makeHtmlArea( XSLT.htmlSolution(((Instance)_instance).toXML()) );
	    return tableComponent;
    }

    JComponent getDotTextComponent() {
	    if (dotComponent != null) return dotComponent;
        final File dotFile = TmpFiles.createHandleToATempFile("dotfile.dot");
        String text;
        final String NL = System.getProperty("line.separator");
        if (dotFile.canRead()) {
            try {
                final StringBuffer b = new StringBuffer((int)dotFile.length()+10); 
                b.append("# ");
                b.append(dotFile.getAbsolutePath());
                b.append(NL);
                final BufferedReader r = new BufferedReader(new FileReader(dotFile));
                String line;
                while ( (line=r.readLine()) != null) {
                    b.append(line);
                    b.append(NL);
                }
                text = b.toString();
            } catch (Exception e) {
                text = "Exception reading " + dotFile.getAbsolutePath() + NL + e;
            }
        } else {
            text = dotFile.getAbsolutePath() + " cannot be read";
        }
	    return dotComponent = makeTextArea(text);
    }

    private JScrollPane makeTextArea(final String text) {
        final JTextArea t = new JTextArea(text);
        t.setEditable(false);

        final Font font = Params.glob.getFontParam("GUI", "textfont");
        t.setFont(font);
        
        // there's something funny about this variable ...
        textFontUpdater = new ParameterListener() {
            public void valueChanged(ParameterEvent e) {
                final Font font = Params.glob.getFontParam("GUI", "textfont");
                t.setFont(font);
            }
            };
        Params.glob.addParameterListener("GUI","textfont",textFontUpdater);
 
        return new JScrollPane(t);
    }
    
    private JScrollPane makeHtmlArea(final String text) {
        final JEditorPane t = new JEditorPane("text/html", text);
        t.setEditable(false);
        setHTMLFont(t);
        
        // there's something funny about this variable ...
        textFontUpdater = new ParameterListener() {
            public void valueChanged(ParameterEvent e) {
                setHTMLFont(t);
            }
            };
        Params.glob.addParameterListener("GUI","textfont",textFontUpdater);
        
        return new JScrollPane(t);

    }


    void openEvalFrame() {
	if (evalFrame == null) {
	    evalFrame = new EvalWindow(getName() + " - Evaluator", _instance);
	    evalFrame.setBounds(0, 0, 500, 300);
	    evalFrame.positionNicely();
	    evalFrame.setDefaultCloseOperation(EvalWindow.HIDE_ON_CLOSE);
	    evalFrame
		.addWindowListener(
				   (WindowListener)AlloySwingUtilities
				   .listener(new WindowAdapter() {
					   public void windowClosing(WindowEvent e) {
					       closeEvalFrame();
					   }
				       }));
	}

	evalFrame.show();
    }

    void closeEvalFrame() {
	if (evalFrame != null)
	    evalFrame.setVisible(false);
    }

    void releaseResources() {
	closeEvalFrame();
	if (evalFrame != null) {
	    evalFrame.dispose();
	    evalFrame = null;
	}
	treeComponent = null;
	textComponent = null;
	xmlComponent = null;
	dotComponent = null;
	if (treeFontUpdater != null)
	    Params.glob.removeParameterListener("GUI","treefont",treeFontUpdater);
	if (textFontUpdater != null)
	    Params.glob.removeParameterListener("GUI","textfont",textFontUpdater);
	super.releaseResources();
    }

	/**
	 * @param t
	 */
	private void setHTMLFont(final JEditorPane t) {
		final Font font = Params.glob.getFontParam("GUI", "textfont");
		final StyleSheet styleSheet = ((HTMLDocument)t.getDocument()).getStyleSheet();
		styleSheet.addRule("H1, H2, H3, body {font-family: " + font.getFamily() + "}");
		styleSheet.addRule("H1, H2, H3, body {font-size: " +  (int)((float)font.getSize()/1.2) + "px}");
	}



}
